package service

import (
	"awesomeProject/app/model"
	"awesomeProject/app/request"
	"awesomeProject/app/response"
	"awesomeProject/global"
	"awesomeProject/util"
	"github.com/fatih/structs"
)

type PermissionSrv struct{}

var casbinSrv CasbinSrv

func (r *PermissionSrv) Pagination(req request.PermissionPagination) response.Resp {
	where := "1=1"
	if req.Keyword != "" {
		where += " AND (`name` LIKE '%" + req.Keyword + "%' or `uri` LIKE '%" + req.Keyword + "%')"
	}
	if req.Group != "" {
		where += " AND `group` = '%" + req.Keyword + "%'"
	}
	offset := (req.PageIndex - 1) * req.PageSize
	var permissions []model.Permission
	err := global.Gorm.Model(&model.Permission{}).Where(where).Offset(offset).Limit(req.PageSize).Find(&permissions).Error
	if err != nil {
		return response.ErrQuery
	}
	var total int64
	err = global.Gorm.Model(&model.Permission{}).Where(where).Count(&total).Error
	if err != nil {
		return response.ErrQuery
	}

	return response.OK.WithData(map[string]interface{}{
		"total": total,
		"list":  permissions,
	})
}

func (r *PermissionSrv) Create(permission model.PermissionFillAble) response.Resp {
	err := global.Gorm.Model(&model.Permission{}).Create(&model.Permission{
		PermissionFillAble: permission,
	}).Error

	if err != nil {
		return response.ErrCreate
	}

	return response.OK
}

func (r *PermissionSrv) FindByID(id uint) model.Permission {
	var permission model.Permission

	_ = global.Gorm.Model(&model.Permission{}).Where("id = ?", id).First(&permission).Error

	return permission
}

func (r *PermissionSrv) QueryByIds(ids []uint) []model.Permission {
	var permissions []model.Permission

	_ = global.Gorm.Model(&model.Permission{}).Where(ids).Find(&permissions).Error

	return permissions
}

func (r *PermissionSrv) Update(id uint, req request.PermissionUpdate) response.Resp {
	obj := r.FindByID(id)
	if obj.ID == 0 {
		return response.ErrRecordNotFound
	}

	updates := structs.Map(req)

	if err := global.Gorm.Model(&obj).Updates(updates).Error; err != nil {
		return response.ErrStore
	}
	// casbin
	_, okUri := updates["uri"]
	_, okMethod := updates["method"]
	if okUri || okMethod {
		if err := casbinSrv.Update(updates["uri"].(string), updates["method"].(string), obj.Uri, obj.Method); err != nil {
			return response.ErrStore
		}
	}

	return response.OK
}

func (r *PermissionSrv) All(superAdmin bool) response.Resp {
	var permissions []model.Permission
	err := global.Gorm.Model(&model.Permission{}).Find(&permissions).Error
	if err != nil {
		return response.ErrQuery
	}
	//if !superAdmin {
	//	for i, permission := range permissions {
	//		if permission.Super == 1 {
	//			permissions[i].Disabled = true
	//		}
	//	}
	//}

	return response.OK.WithData(permissions)
}

func (r *PermissionSrv) Show(id uint) response.Resp {
	permission := r.FindByID(id)
	if permission.ID == 0 {
		return response.ErrRecordNotFound
	}

	return response.OK.WithData(permission)
}

func (r PermissionSrv) Del(id uint) response.Resp {
	permission := r.FindByID(id)
	if permission.ID == 0 {
		return response.ErrRecordNotFound
	}
	err := global.Gorm.Unscoped().Delete(&permission).Error
	if err != nil {
		return response.ErrDel
	}

	var sEnforcer util.SEnforcer
	_, err = sEnforcer.RemoveFilteredPolicy(1, permission.Uri, permission.Method)
	if err != nil {
		return response.ErrDel
	}

	return response.OK
}

func (r PermissionSrv) Destroy(id uint) response.Resp {
	permission := r.FindByID(id)
	if permission.ID == 0 {
		return response.ErrRecordNotFound
	}
	err := global.Gorm.Delete(&permission).Error
	if err != nil {
		return response.ErrDel
	}

	var sEnforcer util.SEnforcer
	_, err = sEnforcer.RemoveFilteredPolicy(1, permission.Uri, permission.Method)
	if err != nil {
		return response.ErrDel
	}

	return response.OK
}

func (r PermissionSrv) Groups() response.Resp {
	var permissionGroups []model.PermissionGroup
	err := global.Gorm.Model(&model.Permission{}).Group("group").Find(&permissionGroups).Error
	if err != nil {
		return response.ErrQuery
	}
	var groups []string
	for _, val := range permissionGroups {
		if val.Group != "" {
			groups = append(groups, val.Group)
		}
	}

	return response.OK.WithData(groups)
}
